<html xmlns="http://www.w3.org/1999/xhtml" id="media-resources">
<head>
    <title>Media Resources</title>
</head>

<body>

<h1>Media Resources</h1>
 
<p>This chapter describes how to include external media resources (images, audio, animation, and video)
into Laszlo applications.</p>

<h2>Overview</h2>
<p>LZX is designed to make it easy for you to integrate media resources into your application
in a flexible and dynamic manner.  You can include images, audio, video, and animations
that were created using standard third-party content creation tools.  
This chapter describes the media formats that are currently supported as 
of LPS 2.0. It then goes on to describes how to integrate and contol 
media in your application.  It concludes with some
optimization tips.</p>

<h2>Supported media types</h2>
<p>
LPS 2.0 and above support the following media types:</p>
<dl>
  <dt>JPEG</dt>
  <dd>All .jpg or .jpeg files are supported.  See the <a target="_blank" href="http://www.w3.org/Graphics/JPEG/">W3C JPEG JFIF Specification</a>.
  <note><i>Progressive</i> files are re-encoded in the LPS.</note>
  </dd>
  <dt>GIF</dt>
  <dd>All .gif files are supported.  See the <a target="_blank" href="http://www.w3.org/Graphics/GIF/spec-gif89a.txt">GIF Spec</a>.
 
  </dd>
  <dt>PNG</dt>
  <dd>All Portable Network Graphics files (<a target="_blank" href="http://www.w3.org/Graphics/PNG/">PNG details at W3C information</a>)
  are supported.  This including PNGs with Alpha channels.</dd>
  <dt>MP3</dt>
  <dd>Support limited to to audio MP3 files with <i>sample</i>-rates of 44.1 kHz, 22.050 kHz, 11.025 kHz, 8.000 kHz and 5.512 kHz</dd>
  <dt>SWF</dt>
  <dd><p>Macromedia Flash (SWF) files. (See <a target="_blank" href="http://www.macromedia.com/software/flash/open/licensing/fileformat/">Macromedia documentation</a>).</p>
  <p>Support is limited to SWF files that contain stills or animation only.  
  Very limited ActionScript is allowed/supported (see below for more details).
  </p></dd>
</dl>

<h2>Views and resources</h2>
<p>
The <tagname link="true">view</tagname> is the most basic viewable 
element in a Laszlo application and it is described in the chapter on <a href="views.html">views</a>.
A view may have a <i>resource</i> attached to it.  The 
resource represents a piece of media (image, audio, video, or animation) that the 
view controls.  For images, the view typically displays the image.  For 
time-based media (audio, video, animation), the view can be used to start, stop, or jump
to a specific frame or time in the media.  </p>
<p>For a simple informal introduction to attaching resources to views, see <xref linkend="art_assets"/>. The chapter you're reading now briefly
goes over topics covered in that tutorial and then goes into greater depth.</p>


<p>Resources may be declared directly inside a view using the view's <attribute>resource</attribute> attribute:</p>
<example title="Importing a resource">
&lt;canvas height="110"&gt;
  &lt;view resource="../resources/logo.gif"/&gt;
&lt;/canvas&gt;
</example>
<p>Or they may be declared externally as first-class objects themselves as: </p>
<example title="Declaring a resource">
&lt;canvas height="110"&gt;
  &lt;resource name="myname" src="../resources/logo.gif"/&gt;
  &lt;view resource="myname"/&gt;
&lt;/canvas&gt;
</example>
<h3>Resources are not views</h3>
<p>
Note that a<tagname link="true">resource</tagname>is <i>not</i> itself a view.
 Resources do no have x and y positions, or background color,
or an of the forty-nine or so attributes that views have. A resource that is not attached to a view is essentially invisible to the
application. As explained below, in order to manipulate a resource, you performe actions on the view to which the resource is attached.
</p>
<h3>Summary of APIs that act on resources</h3>
<p>There are a number of view APIs (methods, fields, and events) that can 
be used to find out about and control a view's resource.</p>
<ul>
    <li>Resource and view size, scaling and stretching:
        <ul>
            <li><field link="true">LzView.resourcewidth</field></li>
            <li><field link="true">LzView.resourceheight</field></li>
            <li><field link="true">LzView.xscale</field></li>
            <li><field link="true">LzView.yscale</field></li>
            <li><field link="true">LzView.stretches</field></li>
            <li><method link="true">LzView.stretchResource()</method></li>
            <li><field link="true">LzView.measureWidth()</field></li>
            <li><field link="true">LzView.measureHeight()</field></li>
            <li><field link="true">LzView.updateResourceSize()</field></li>
        </ul>
        <p><fixme>Discuss how view and resource sizes interact (need details
        from Adam/Sarah since I'm not really sure)</fixme></p>
    </li>
    <li>Resource loading (discussed <a href="#loading">below</a>):
        <ul>
            <li><field link="true">LzView.resource</field></li>
            <li><method link="true">LzView.setSource()</method></li>
            <li><method link="true">LzView.unload()</method></li>
            <li><field link="true">LzView.loadratio</field></li>
            <li><field link="true">LzView.framesloadratio</field></li>
            <li><event link="true">LzView.onload</event></li>
            <li><event link="true">LzView.onerror</event></li>
            <li><event link="true">LzView.ontimeout</event></li>
            <!-- edb: woa. the following looks strange -->
            <li><event link="true">LzView.onaddsubresource</event></li>
        </ul>
    </li>
    <li>Animation/video/frames:
        <ul>
            <li><method link="true">LzView.play()</method></li>
            <li><method link="true">LzView.stop()</method></li>
            <li><method link="true">LzView.seek()</method></li>
            <li><method link="true">LzView.getTotalTime()</method></li>
            <li><method link="true">LzView.getCurrentTime()</method></li>
            <li><method link="true">LzView.setResourceNumber()</method></li>
            <li><field link="true">LzView.frame</field></li>
            <li><field link="true">LzView.totalframes</field></li>
            <li><event link="true">LzView.onlastframe</event></li>
            <li><event link="true">LzView.onplay</event></li>
            <li><event link="true">LzView.onstop</event></li>
        </ul>
    </li>
    <li>Audio:
        <ul>
            <li><method link="true">LzView.getVolume()</method></li>
            <li><method link="true">LzView.setVolume()</method></li>
            <li><method link="true">LzView.getPan()</method></li>
            <li><method link="true">LzView.setPan()</method></li>
            <li><method link="true">LzView.play()</method></li>
            <li><method link="true">LzView.stop()</method></li>
            <li><method link="true">LzView.getTotalTime()</method></li>
            <li><method link="true">LzView.getCurrentTime()</method></li>
        </ul>
    </li>
</ul>
<h3>Resource declarations and naming</h3> 
<p>
When a resource is declared externally, it must be given a name.  The namespace for resources is
global to the entire application. Resource tags can only be used
as direct children of either the <tagname link="true">canvas</tagname> or <tagname link="true">library</tagname> tags. </p>

<p>This style of resource inclusion makes it simpler to separate out art assets from code
and can make for improved designer/developer interactions.</p>

<p>When you directly import a resource without naming it, as in the first example,
the LZX compiler assigns a unique name to that resource.</p>
<p>Behavior when two resources share the same name is undefined. Therefore you should take care to make sure that each resource
has a unique and appropriate name.</p>


<h2>Multi-frame resources</h2>
<p>Laszlo supports the notion of a resource 
<tagname link="true">frame</tagname>.  
A multi-frame resource is a resource that has a single name but refers 
to multiple independent pieces of media that are sequenced.  Here is
an example of declaring a multi-frame resource:
</p>
<example title="Declaring a multi-frame resource">
&lt;canvas height="180"&gt;
  &lt;resource name="myresource"&gt;
    &lt;frame src="../resources/logo.gif"/&gt;
    &lt;frame src="../resources/sky.jpg"/&gt;
  &lt;/resource&gt;
  &lt;simplelayout spacing="5"/&gt;
  &lt;view id="myview" resource="myresource"/&gt;
  &lt;view layout="axis: x; spacing: 3"&gt;
    &lt;text&gt;Frame:&lt;/text&gt;
    &lt;radiogroup&gt;
      &lt;radiobutton selected="true"&gt;1&lt;/radiobutton&gt;
      &lt;radiobutton&gt;2&lt;/radiobutton&gt;
      &lt;method event="onvalue" args="v"&gt;
        myview.setResourceNumber(Number(v));
      &lt;/method&gt;
    &lt;/radiogroup&gt;
  &lt;/view&gt;
&lt;/canvas&gt;
</example>
<p>
You can use a multi-frame resource to construct up an animation that
moves between frames when you call the 
<api link="true">LzView.play()</api> method.  Conversely,
when you import a resource that contains an animation, each frame of the 
animation automatically becomes a frame in that resource.
In other words, art assets that contain multiple frames themselves <i>are</i>
multi-frame resources.  Just as with multi-frame resources that are
constructed in LZX by importing each frame individually, 
you can control the frame that is currently displayed.</p>
<example title="Importing an animation">
&lt;canvas height="220"&gt;
  &lt;simplelayout spacing="5"/&gt;
  &lt;resource name="myresource" src="resources/logo.swf"/&gt;
  &lt;button onclick="me.stop()"&gt; Stop &lt;/button&gt;
  &lt;button onclick="me.play()"&gt; Play &lt;/button&gt;
  &lt;text text="${me.frame + ' out of ' + me.totalframes + ' frame(s)'}"/&gt;
  &lt;view layout="axis: x; spacing: 4"&gt;
    &lt;button isdefault="true" text="Set current frame: " 
      onclick="me.setAttribute('frame', Number(tt.text))"/&gt;
    &lt;edittext id="tt" width="50"/&gt;
  &lt;/view&gt;
  &lt;view id="me" resource="myresource"/&gt;
&lt;/canvas&gt;
</example>
<p>
Multi-frame resources are also useful for structuring the display of a single visual element
or component that takes on different appearances:
</p>
<example title="Using multi-frame resources">
&lt;canvas height="120"&gt;
  &lt;!-- create the multi-frame resource and give it a name --&gt;
  &lt;resource name="mybutton_rsrc"&gt;
    &lt;!-- first frame is the mouseup state of the button --&gt;     
    &lt;frame src="../resources/button-up.png"/&gt;   
    &lt;!-- second frame is the mouseover state of the button --&gt;     
    &lt;frame src="../resources/button-over.png"/&gt; 
    &lt;!-- third frame is the mousedown state of the button --&gt;     
    &lt;frame src="../resources/button-down.png"/&gt; 
  &lt;/resource&gt;

  &lt;!-- attach the resource to a view with mouse events --&gt;
  &lt;view resource="mybutton_rsrc" 
        onmouseover="setResourceNumber(2)"
        onmouseout="setResourceNumber(1)"
        onmousedown="setResourceNumber(3)"
        onmouseup="setResourceNumber(2)"/&gt;

&lt;/canvas&gt;
</example>

<h3>Frame rates</h3>
<p>In LPS 2.0, all LZX applications are compiled to Macromedia
Flash (SWF) files.  With the excpetion of audio files noted below, SWF files are played by the Flash plugin at a
fixed frame rate and all imported animations are played at that frame
rate.  As of LPS 2.0, this frame rate is fixed at 30 frames per
second. </p>
<h4>Audio rates</h4>
<p>
  Animations that include an audio sound track are played
at a rate that maintains the original audio/video synchronization in
the incoming animation.</p>

<h2><a name="loading">Resource loading</a></h2>
<p>In the examples above, we've declaratively tied resources to view.
But we haven't expressed anything about when or how the application
should pull in the needed resource.  We call this <dfn>resource
loading</dfn> and LZX provides a variety of control over how and when
the application loads resources.  The most important choice is whether
a resource should be loaded at <glossterm>compile time</glossterm> or
<glossterm>run time</glossterm>.</p>

<h3>Compile time resources</h3>
<p>
Resources that are loaded at compile time are included in the application 
binary and add to the initial download size of the application.</p>

<example extract="false" title="Including a resource at compile time">
  &lt;resource name="myname" src="resources/logo.gif"/&gt;
</example>

<p>Compile-time resource inclusion is good for </p>
<ul>
    <li>small assets that are fixed for the life-time of the running application.</li>
    <li>assets that are needed by all users of an application</li>
</ul>
<p>
Examples of resources that are included at compile time include most
of the assets associated with user-interface componentry.  
</p>
<p>The LZX compiler may transcode compile-time resources for inclusion in
the SWF application; the LPS caches the results of these transcodes.
The compiler checks the last-modified time of all compile-time-included 
resources to determine if an application needs to be recompiled.</p>

<h3><a name="runtime-resources"/>Run-time resources</h3>
<p>There are two main ways to load resources at run-time.  The first is to use
special syntax that is understood by the <tagname link="true">view</tagname>'s 
<code>resource</code> attribute.  If you specify a value for this attribute that
is an HTTP url, the compiler assumes that this resource should be loaded at runtime:</p>
<example title="Loading a resource at runtime">
&lt;canvas height="180"&gt;
  &lt;view resource="http:../resources/logo.gif"/&gt;
&lt;/canvas&gt;
</example>

<p>The second method is to use the <method link="true">LzView.setSource()</method> method.
The previous example is equivalent to the following one:</p>
<example title="Loading a resource at runtime via script">
&lt;canvas height="180"&gt;
  &lt;view oninit="this.setSource('http:../resources/logo.gif')"/&gt;
&lt;/canvas&gt;
</example>

<note>LZX treats HTTP URLs that omit the two slashes <code>//</code> after the colon (:) as being
relative to the application.</note>
<p>
<method link="true">LzView.setSource()</method> provides more contol over
the loading of the resource.  Using this method, you can:</p>
<ul>
    <li>choose whether or not the server and/or client should cache the resource;</li>
    <li>specify an URL that instructs the server to use a specific protocol to
    fetch the resource;</li>
    <li>specify HTTP request headers that should be used when fetching the resource
    over HTTP.</li>
</ul>

<h4>Protocols</h4>
<p>
Before sending resources to a running Laszlo application,
the LPS first fetches (or proxies) the resource.  The LPS uses
the URL for the resource to determine how and where to get the resource.
The term <i>back-end</i> is used to refer to the server that is 
ultimately providing the resource.  Depending on your
configuration, the back-end can be the LPS server
host itself.   Or it may be another distinct host.
</p>
<p>
The LPS determines the protocol to use to communicate to the back-end
based on the URL for the resource.  By default, URLs that are to be
loaded at runtime, that don't specify the protocol are assumed to be
HTTP urls.  LPS 2.0 supports communication to back-end hosts 
(including localhost itself) via the HTTP protocol.  
Relative HTTP URLs are thus fetched using a localhost HTTP transfer. 
</p>

<p>
LPS also supports a special <code>file:</code> protocol.  URLs that
use this protocol are read directly from the local file systems.
Relative file URLs are relative to the location of the application.
In general, <code>file:</code> URL access reduces load on the server
(one fewer socket and thread per request).
</p>


<h4>Caching</h4>
<p>
By default, media that is accessed at runtime is cached both in the
server <em>and</em> in the client browser.  The LPS uses the standard
HTTP If-Modified-Since/Last-Modified caching mechanism specified in the <a
href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">HTTP 1.1
spec</a>.</p>

<p>
The LPS server actually maintains two media caches.  One cache is used
for resources that are requested at runtime.  This is simply called
the <dfn>Media Cache</dfn>.  It also maintains a second cache for
resources that are compiled into applications called the <dfn>Compiler
Media Cache</dfn>.  In general, the Compiler Media Cache settings only
affect the speed of the LPS compiler.  The settings for the Media
Cache can affect server performance.  See <xref
linkend="deployers-guide"/>for details.
</p>

<p>
The example below provides a text input area for you to type in urls that
you'd like to test:
</p>

<example title="Testing runtime resource loading">
&lt;canvas height="400"&gt;
  &lt;font src="helmetr.ttf" name="helvet"/&gt;
  &lt;simplelayout spacing="3"/&gt;

  &lt;view&gt;
    &lt;simplelayout axis="x" spacing="2"/&gt;
    &lt;text valign="middle"&gt;Type url:&lt;/text&gt;
    &lt;edittext width="500" id="url"&gt;http:../resources/logo.gif&lt;/edittext&gt;
  &lt;/view&gt;
  &lt;text&gt;(also try resources/logo.swf)&lt;/text&gt;

  &lt;command onselect="butt.doit();"  key="['Enter']" active="true"/&gt;

  &lt;checkbox text="Cache in client" id="ccache"/&gt;
  &lt;checkbox text="Cache in server" id="scache"/&gt;

  &lt;button id="butt"&gt;Make request
    &lt;method event="onclick"&gt;
      this.doit();
    &lt;/method&gt;

    &lt;method name="doit"&gt;
    &lt;![CDATA[
      status.setText("Requesting: " + url.getText()); 

      // Determine caching from checkboxes
      var caching = 'none'
      if (ccache.getValue() &amp;&amp; scache.getValue()) {
          caching = 'both';
      } else if (ccache.getValue()) {
          caching = 'clientonly';
      } else if (scache.getValue()) {
          caching = 'serveronly';
      }

      me.setSource(url.getText(), caching) ;
    ]]&gt;&lt;/method&gt;
  &lt;/button&gt;
  &lt;button onclick="me.stop()"&gt; Stop &lt;/button&gt;
  &lt;button onclick="me.play()"&gt; Play &lt;/button&gt;
  &lt;text text="${me.frame + ' out of ' + me.totalframes + ' frame(s)'}"/&gt;
  &lt;text multiline="true" width="200" height="100" id="status"/&gt;
  &lt;view id="me"&gt;
    &lt;method event="onload" args="e"&gt;
      status.setText('loaded: ' + e);
    &lt;/method&gt;
    &lt;method event="onerror" args="e"&gt;
      status.setText('error: ' + e);
    &lt;/method&gt;
    &lt;method event="ontimeout" args="e"&gt;
      status.setText('timeout: ' + e);
    &lt;/method&gt;
  &lt;/view&gt;
&lt;/canvas&gt;
</example>

</body>
</html>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2001-2004 Laszlo Systems, Inc.  All Rights Reserved.              *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
